/**
 * @author paim 05/05/2010
 */
package paim.wingchun.tarefa;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import paim.wingchun.app.WC_Utils;

public class CTarefa implements Runnable, IMonitorProgresso {

    Dialogo dialogo;

    Vector<String> mensagens = new Vector<String>();

    boolean showCount = false;

    int count = 0;

    private List<Barra> barras = new ArrayList<Barra>(1);

    private VGTarefa visao;

    private Tarefa tarefa;

    private IEventoGenerico fimTarefa = new IEventoGenerico() {

        @Override
        public void onEvent(Object[] Objetos) {
            estadoFechar();
        }
    };

    private List<ActionListener> listenersFechar = new ArrayList<ActionListener>();

    /** permite fechar antes terminar tarefa */
    private boolean canclose = true;

    private boolean canClose() {
        return this.canclose;
    }

    public CTarefa(JFrame owner, String titulo, Integer largura, Integer altura, boolean temMenssagem,
            boolean showCount, boolean isModal) {
        this.showCount = showCount;

        dialogo = new Dialogo(owner, titulo, isModal);
        dialogo.configure(visao = new VGTarefa(), new Dimension(largura, altura));

        getVisao().setVisiblePainelLista(temMenssagem);
        getVisao().getPBotoes().setVisible(temMenssagem);
        getVisao().getBtCancelar().addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                acaoCancelar();
            }
        });

        getVisao().getBtFechar().addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                acaoFechar();
            }
        });

        getBarras().add(new Barra(0));
    }

    public Dialogo getDialogo() {
        return this.dialogo;
    }

    public List<Barra> getBarras() {
        return this.barras;
    }

    public VGTarefa getVisao() {
        return visao;
    }

    public String getRotulo() {
        return getVisao().getLabel().getText();
    }

    @Override
    public void addMenssagem(String mensagem) {
        verificaTarefaCancelada();
        getTarefa().setMensagem(mensagem);
        putMensagem(mensagem);
    }

    @Override
    public Barra getBarra(int n) {
        return getBarras().get(n);
    }

    @Override
    public Barra getBarra() {
        return getBarras().get(0);
    }

    @Override
    public void setRotulo(String msg) {
        if ( msg.toLowerCase().trim().startsWith("<html") )
            getVisao().getLabel().setText(msg);
        else getVisao().getLabel().setText(WC_Utils.strToHtml(msg));
        getVisao().getLabel().repaint();
    }

    @Override
    public void run() {
        getDialogo().setVisible(true);
    }

    @Override
    public void termina() {
        if ( !visao.isVisiblePainelLista() )
            acaoFechar();
        else estadoFechar();
    }

    public void mostra() {
        new Thread(this, "Mensagem Progresso").start();
    }

    @Override
    public Component getComponentPai() {
        return getDialogo();
    }

    /** Para permitir o cancelamento da tarefa a partir do botão "Cancelar" da barra de progresso. */
    @Override
    public void setTarefa(Tarefa tarefa, boolean canCancel, boolean canCloser) {
        if ( getTarefa() != tarefa && getTarefa() != null ) {
            getTarefa().getEventosFimTarefa().remove(this.fimTarefa);
        }

        this.tarefa = tarefa;
        getTarefa().getEventosFimTarefa().add(this.fimTarefa);
        this.canclose = canCloser;

        /*Se tarefa "realmente existir", habilita o botão "Cancelar"*/
        if ( getTarefa() != null && canCancel ) {
            getVisao().getBtCancelar().setVisible(true);
            getVisao().getBtCancelar().setEnabled(true);
        }
    }

    public Tarefa getTarefa() {
        return this.tarefa;
    }

    /** Listener chamada quando janela de progresso for efetivamente fechada */
    @Override
    public void adicionaListenerFechar(ActionListener actionListener) {
        listenersFechar.add(actionListener);
    }

    private void acaoFechar() {
        if ( getDialogo() != null ) {
            getDialogo().setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
            getDialogo().dispose();
            getDialogo().setVisible(false);
        }
        /* Executa listeners */
        for ( ActionListener listener : listenersFechar ) {
            listener.actionPerformed(new ActionEvent(this, 0, "fecha"));
        }
    }

    private void estadoFechar() {
        if ( getVisao() != null && getDialogo() != null ) {
            getVisao().getBtCancelar().setEnabled(false);
            if ( !canClose() )
                getVisao().getBtFechar().setEnabled(getTarefa().isTerminou());
            else getVisao().getBtFechar().setEnabled(true);
            getDialogo().toFront();
        }
    }

    private void acaoCancelar() {
        getTarefa().setDeveCancelar(true);
        setRotulo(getRotulo() + "Cancelamento solicitado");
        getVisao().getLabel().setBlinking(true);
        getVisao().getLabel().setForegroundBL(Color.red);
        estadoFechar();
    }

    private void putMensagem(final String mensagem) {
        SwingUtilities.invokeLater(new Runnable() {

            /*usa thread do swing para adicionar a msg (evita problemas de sincronismo...)*/
            @SuppressWarnings("unchecked")
            @Override
            public void run() {
                String novaMensagem = mensagem;
                if ( showCount ) {
                    count++;
                    novaMensagem = WC_Utils.insereZerosAEsquerda(count, 3) + ". " + novaMensagem;
                }
                mensagens.add(novaMensagem);
                getVisao().getLista().setListData(mensagens);

                int ultimoIndice = getVisao().getLista().getModel().getSize() - 1;
                Object ultimaMensagem = getVisao().getLista().getModel().getElementAt(ultimoIndice);
                getVisao().getLista().setSelectedValue(ultimaMensagem, true);
            }
        });
    }

    private void verificaTarefaCancelada() {
        if ( getTarefa().getDeveCancelar() ) {
            putMensagem("Operação cancelada pelo usuário.");
            throw new ExcecaoCancelamento();
        }
    }

    public class Dialogo extends JDialog {

        private static final long serialVersionUID = 1L;

        boolean containMensagem = false;

        public Dialogo(Frame owner, String title, boolean modal) throws HeadlessException {
            super(owner, title, modal);
        }

        public Dialogo(Frame owner, String title, boolean modal, boolean containMensagem) throws HeadlessException {
            super(owner, title, modal);
        }

        public void setContainMensagem(boolean b) {
            this.containMensagem = b;
        }

        public boolean containMensagem() {
            return this.containMensagem;
        }

        public void configure(VGTarefa vgjsMensagemProgressoPaim, Dimension d) {
            this.setContentPane(vgjsMensagemProgressoPaim);

            setAlwaysOnTop(getOwner() == null || !getOwner().isShowing());
            setModal(true);

            setUndecorated(false);
            setResizable(true);
            setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);

            /*Adicionando um novo listener de janela, para permitir cancelar a tarefa no botão "X", quando for o caso.*/
            addWindowListener(new ListenerJanela());
            pack();
            setSize(d);
            setLocationRelativeTo(getOwner());
            toFront();

        }

    }

    public class Barra {

        int n = 0;

        private Barra() {
            super();
        }

        public Barra(int n) {
            this();
            this.n = n;
            if ( n >= 1 ) {
                getVisao().addJProgressBar();
            }
        }

        public void setRotulo(String s) {
            getVisao().getjLabelsBar().get(n).setText(
                    WC_Utils.formatarValorDecimal(getPercentComplete() * 100, 0) + "%  -  " + s);
            getVisao().getjLabelsBar().get(n).repaint();
        }

        public void completa() {
            getVisao().getjProgressosBar().get(n).setValue(getVisao().getjProgressosBar().get(n).getMaximum());
            // setRotuloBarra(UtilitariosString.formatarValorDecimal(getPercentComplete(nPBar) * 100, 0) + "%  -  ",
            // nPBar);

        }

        public void limpa() {
            verificaTarefaCancelada();
            getVisao().getjProgressosBar().get(n).setValue(0);

            setRotulo("");
        }

        public void incrementa() {
            verificaTarefaCancelada();
            getVisao().getjProgressosBar().get(n).setValue(getVisao().getjProgressosBar().get(n).getValue() + 1);
        }

        public void setIndeterminate(boolean b) {
            getVisao().getjProgressosBar().get(n).setIndeterminate(b);
        }

        public void setMaximo(int max) {
            getVisao().getjProgressosBar().get(n).setMaximum(max);
        }

        public double getPercentComplete() {
            return getVisao().getjProgressosBar().get(n).getPercentComplete();
        }
    }

    private class ListenerJanela implements WindowListener {

        @Override
        public void windowActivated(WindowEvent e) {}

        @Override
        public void windowClosed(WindowEvent e) {
            dialogo = null;
        }

        @Override
        public void windowClosing(WindowEvent e) {
            /*Se o botão "Fechar" estiver habilitado, permite fechar a janela no botão "X"*/
            if ( getVisao().getBtFechar().isEnabled() && (canClose() || getTarefa().isTerminou()) )
                acaoFechar();
            /* Botão "Fechar" desabilitado - logo, tarefa ainda em andamento.*/
            /*Se a opção "Cancelar" estiver sendo usada (neste caso, "tarefa != null", então executa a ação deste botão.*/
            else if ( getVisao().getBtCancelar().isEnabled() ) {
                acaoCancelar();
            }
        }

        @Override
        public void windowDeactivated(WindowEvent e) {}

        @Override
        public void windowDeiconified(WindowEvent e) {}

        @Override
        public void windowIconified(WindowEvent e) {}

        @Override
        public void windowOpened(WindowEvent e) {}
    }

}
